package com.tiancheng.trade.merchant.util;


import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: likailun
 * @Description: 大数据请求工具类
 * @Date: create in 2021/7/19 10:00 上午
 */
@Component
public class BigDataRequest {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private String bigDataTokenKey = "bigDataTokenKey";
    @Value("${bigData.bigDataUrl}")
    private String bigDataUrl;
    @Value("${bigData.bigDataAppId}")
    private String bigDataAppId;
    @Value("${bigData.bigDataAppSecret}")
    private String bigDataAppSecret;

    @SneakyThrows
    public JSONObject getRequest(String api, Map<String, Object> params) {
        String url = getSiginUrl(api, params, null);
        String s = HttpUtil.get(url);
        JSONObject data = JSONObject.parseObject(s).getJSONObject("data");
        return data;
    }

    @SneakyThrows
    public JSONObject postRequest(String api, Map<String, Object> urlParams, Object body) {
        String url = getSiginUrl(api, urlParams, body);
        String s = HttpUtil.post(url, JSONObject.toJSONString(body));
        JSONObject data = JSONObject.parseObject(s).getJSONObject("data");
        return data;
    }

    private String getSiginUrl(String api, Map<String, Object> params, Object body) {
        if (params == null) {
            params = new HashMap<>();
        }
        String bitDataPath = bigDataUrl;
        String appId = bigDataAppId;
        int timestamp = (int) (System.currentTimeMillis() / 1000);
        String nonce = UUID.randomUUID().toString();
        params.put("appid", appId);
        params.put("nonce", nonce);
        params.put("timestamp", timestamp);
        /** 参数字典序 */
        List<String> paramKeys = new LinkedList<String>(params.keySet());
        Collections.sort(paramKeys, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o1.compareTo(o2);
            }
        });
        /** ----参数字典序结束---- */
        int i = 0;
        String signData = api;
        for (String param : paramKeys) {
            if (i == 0) {
                signData += "?" + param + "=" + params.get(param);
            } else {
                signData += "&" + param + "=" + params.get(param);
            }
            i++;
        }
        String apiAndParams = signData;
        if (body != null) {
            String bodyString = null;
            if (String.class.isAssignableFrom(body.getClass())) {
                bodyString = (String) body;
            } else {
                bodyString = JSON.toJSONString(body);
            }
            signData += bodyString;
        }
        String sign = null;
        if (BigDataApi.token.equals(api)) {
            sign = generateSign(signData, bigDataAppSecret);
        } else {
            sign = generateSign(signData, getToken());
        }
        return bitDataPath + apiAndParams + "&sign=" + sign;
    }

    /**
     * HmacSHA1加密
     */
    private String genHMAC(String data, String key) {
        // 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
        SecretKeySpec signinKey = null;
        try {
            signinKey = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1");
        } catch (UnsupportedEncodingException e1) {
            throw new RuntimeException(e1);
        }
        // 生成一个指定 Mac 算法 的 Mac 对象
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA1");
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        // 用给定密钥初始化 Mac 对象
        try {
            mac.init(signinKey);
        } catch (InvalidKeyException e) {
            throw new RuntimeException(e);
        }
        // 完成 Mac 操作
        byte[] rawHmac = null;
        try {
            rawHmac = mac.doFinal(data.getBytes("UTF-8"));
        } catch (IllegalStateException | UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        String result = Base64.getEncoder().encodeToString(rawHmac);
        return result;
    }

    /**
     * 生成请求api签名
     */
    private String generateSign(String api, String key) {
        String hmacKey = genHMAC(api, key);
        try {
            hmacKey = URLEncoder.encode(hmacKey, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
        return hmacKey;
    }

    /**
     * 获取token
     */
    public String getToken() {
        String redisBigDataToken = stringRedisTemplate.opsForValue().get(this.bigDataTokenKey);
        if (redisBigDataToken != null) {
            return redisBigDataToken;
        } else {
            synchronized (this) {
                redisBigDataToken = stringRedisTemplate.opsForValue().get(this.bigDataTokenKey);
                if (redisBigDataToken != null) {
                    return redisBigDataToken;
                }
                JSONObject data = getRequest(BigDataApi.token, null);
                String token = data.getString("token");
                Integer expire = data.getInteger("expire");
                stringRedisTemplate.opsForValue().set(this.bigDataTokenKey, token,
                        (expire - (System.currentTimeMillis() / 1000)), TimeUnit.SECONDS);
                return token;
            }
        }
    }

    public static class BigDataApi {
        public static String token = "/token";
    }
}
